package registry

import (
	"context"
)

// Registrar Service registration interface 服务注册接口
type Registrar interface {
	// Register 注册
	Register(ctx context.Context, service *ServiceInstance) error
	// Deregister 注销
	Deregister(ctx context.Context, service *ServiceInstance) error
}

// Discovery Service Discovery Interface 服务发现接口
type Discovery interface {
	// GetService 获取服务实例
	GetService(ctx context.Context, serviceName string) ([]*ServiceInstance, error)
	// Watch 创建服务监听器
	Watch(ctx context.Context, serviceName string) (Watcher, error)
}

type Watcher interface {
	// Next 获取服务实例, next在下面的情况下会返回服务
	//1. 第一次监听时，如果服务实例列表不为空，则返回服务实例列表
	//2. 如果服务实例发生变化，则返回服务实例列表
	//3. 如果上面两种情况都不满足，则会阻塞到context deadline或者cancel
	Next() ([]*ServiceInstance, error)
	// Stop actively give up listening 主动放弃监听
	Stop() error
}

type ServiceInstance struct {
	// Service ID registered with the registry center. 注册到注册中心的服务id
	ID string `json:"id"` // 注册id
	// Service name
	Name string `json:"name"` // 注册名称
	// Service version
	Version string `json:"version"`
	// Service metadata 服务元数据
	Metadata map[string]string `json:"metadata"`
	// Service path
	// http://127.0.0.1:8000
	// grpc://127.0.0.1:9000
	// 用于服务的注册 填写被发现的ip和端口 如: gin客户端 grpc服务端  等
	Endpoints []string `json:"endpoints"`

	Tags []string `json:"tags"`
}

// Balancer is balancer interface，所有的负载均衡算法需要实现这个方法，达到选择出需要节点的目的
type Balancer interface {
	Pick(ctx context.Context, nodes []Node) (selected Node, err error)
}

// Node is node interface. 不同的负载均衡算法有不同的实现
type Node interface {
	// Key 存放在map中的key
	Key() string

	// Scheme is service node scheme
	Scheme() string

	// Address is the unique address under the same service
	Address() string

	// ServiceName is service name
	ServiceName() string

	Weight() int64

	UpdateWeight(weight int64)

	// Version is service node version
	Version() string

	// Metadata is the kv pair metadata associated with the service instance.
	// version,namespace,region,protocol etc..
	Metadata() map[string]string

	// Instance 获取实例
	Instance() interface{}

	// SetInstance 设置实例
	SetInstance(instance interface{})

	// Tags 获取tags
	Tags() []string
}

type Resolver interface {
	Next(ctx context.Context) (selected Node, err error)
}
